(require 'workspace-model)
(require 'class)
(require 'as-load)

(defvar *prefix-reg* "[.\s\t\r\n():;{}]")
(defvar *symbol-reg* "[.;:()\r\n/]")
(defvar *word-reg* "[^_a-zA-Z0-9][_a-zA-Z0-9]+")

(setq completion-ignore-case 't)
(global-set-key "\t" 'override-tab)



(defun get-word-backward ()
  (let ((buffer nil))
    (search-backward-regexp *word-reg*)  
    (setq buffer (match-string-no-properties 0))
    (string-match "[_a-zA-Z0-9]+$" buffer)
    (match-string-no-properties 0 buffer)))

(defun expand (key-map)
  (interactive)

  (let* ((point (point))
	 (prefix-head  (+ (search-backward-regexp *prefix-reg*) 1))
	 (matched-list '()))
    (goto-char point)
    (completion-in-region prefix-head point (get-expand-list key-map))))


(defun get-expand-list(key-map)
  (save-excursion 
    (let* ((point (point))
	   (symbol "")
	   (list-buffer '())
	   (symbol-index nil)
	   (type nil))
      (setq symbol-index (search-backward-regexp *symbol-reg*))
      (setq symbol (match-string-no-properties 0))
      (cond ((equal symbol ".")
	     ;;get instance name
	     (goto-char symbol-index)
;	     (debug)
	     (setq type (get-declaration (get-word-backward)))
	     ;;get functions
	     (setq list-buffer (get-function-list type))
	     (setq list-buffer (append list-buffer (get-variable-list type))))
	    ((equal symbol ":")
	      (setq list-buffer (get-class-names)))
	    ('t
	     (goto-char point)
	     (let* ((prefix-head (+ 1 (search-backward-regexp *prefix-reg*) )))
		   (setq list-buffer key-map)
		   (setq list-buffer (append (get-variable-list) list-buffer))
		   (setq list-buffer (append (get-function-list) list-buffer)))))
      list-buffer)))


(defun get-declaration (instance-name)
  (save-excursion
  (let ((str-buffer ""))
    (search-backward-regexp (concat "var[\s\t\r\n]+" instance-name "[\s\t\r\n]*:[\s\t\r\n]*[a-zA-Z0-9_]+"))
    (setq str-buffer (match-string-no-properties 0))
    (string-match "[a-zA-Z0-9_]+$" str-buffer)
    (match-string-no-properties 0 str-buffer))))


(defun get-function-list (&optional classname)
  (condition-case nil
  (let* ((list-buffer '())
	 (name-buffer "")
	 (function-list '()))
    (refresh-current-file)
    (cond (classname
	   (setq function-list (oref (get-class classname) functions)))
	  ('t
	   (setq function-list (oref (get-current-class) functions))))
    (dolist (function function-list)
	     (setq name-buffer (oref function name))
	     (unless (assoc-string name-buffer list-buffer 't)
	       (push name-buffer list-buffer)))
    list-buffer)
  (error "no variable or method is found")))

(defun get-variable-list (&optional classname)
  (condition-case nil
  (let* ((list-buffer '())
	 (name-buffer "")
	 (variable-list '()))
    (refresh-current-file)
    (cond (classname
	  (setq variable-list (oref (get-class classname) variables)))
	  ('t
	   (setq variable-list (oref (get-current-class) variables))))
    (dolist (variable variable-list)
      (setq name-buffer (oref variable name))
      (unless (assoc-string name-buffer list-buffer 't)
	(push name-buffer list-buffer)))
    list-buffer)
  (error "no variable or method is found")))




(provide 'completion)